#include "MiniMesh.h"

#define ACCURACY 1e-12
#define MIN(a, b) ((a) > (b) ? (b) : (a))
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define SIGN(x) ((x) > 0 ? 1 : -1)

using namespace XYF;

MiniMesh::MiniMesh(MeshType type) : m_type(type)
{
    // 需要默认构造材质，默认为纯白色
    m_material.alpha = 100;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            m_material.R[i * 3 + j] = 1;
}

MiniMesh::~MiniMesh()
{
    for (auto it = m_vList.begin(); it != m_vList.end(); ++it)
        if ((*it) != nullptr)
            delete *it;
    for (auto it = m_eList.begin(); it != m_eList.end(); ++it)
        if ((*it) != nullptr)
            delete *it;
    for (auto it = m_fList.begin(); it != m_fList.end(); ++it)
        if ((*it) != nullptr)
            delete *it;
}

int MiniMesh::GetType()
{
    return MiniObject::mesh;
}

// 创建顶点，并返回指针
vertex3f *MiniMesh::CreateVertex(Vector3f p, bool testSame)
{
    // 如果开启检测，会禁止构造重合的顶点
    if (testSame)
    {
        for (auto it = m_vList.begin(); it != m_vList.end(); ++it)
        {
            // 返回重合顶点
            if (length((*it)->pos - p) < ACCURACY)
                return *it;
        }
    }
    vertex3f *vp = new vertex3f({p, nullptr, 0});
    m_vList.push_back(vp);
    return vp;
}

// 创建三角面，可选自动衔接
face *MiniMesh::CreateFace(vertex3f *v0, vertex3f *v1, vertex3f *v2, bool autoTwin)
{
    // 创建三角形面
    vertex3f *vList[] = {v0, v1, v2};
    face *f = CreateFace(vList, 3, autoTwin);
    return f;
}

// 创建四边形面，默认自动判定衔接相邻面
face *MiniMesh::CreateFace(vertex3f *v0, vertex3f *v1, vertex3f *v2, vertex3f *v3, bool autoTwin)
{
    // 判断四点是否共面，如果不共面，转为建立两个三角面
    if (!onFace(v0->pos, v1->pos, v2->pos, v3->pos))
    {
        // 注意创建顺序：先创建左下角的三角形，然后创建右上角的三角形
        // 这个顺序的目的是当从左向右，从下向上创建面时，不会出现流形情况
        CreateFace(v0, v1, v3);
        CreateFace(v1, v2, v3);
        return nullptr;
    }

    // 创建四边形面
    vertex3f *vList[] = {v0, v1, v2, v3};
    face *f = CreateFace(vList, 4, autoTwin);
    return f;
}

// 创建多边形面
face *MiniMesh::CreateFace(vertex3f **vList, int n, bool autoTwin)
{
    // 有一个顶点为空，就退出
    for (int i = 0; i < n; i++)
        if (vList[i] == nullptr)
            return nullptr;

    face *f = new face;
    half_edge **eList = new half_edge *[n];

    // 创建半边
    for (int i = 0; i < n; i++)
        eList[i] = new half_edge;

    // 初始化半边
    for (int i = 0; i < n; i++)
    {
        half_edge *e = eList[i];

        e->v = vList[i];
        e->incFace = f;
        e->next = eList[(i + 1) % n];
        e->prev = eList[(i + n - 1) % n];
        e->twin = nullptr;
    }

    // 面持有任意一个半边
    f->e = eList[0];

    // 默认自动衔接面
    if (autoTwin)
        CreateTwin(f);

    // 如果顶点没有半边，就赋予半边，放在这里，因为如果顶点没有半边，不需要计算邻面
    for (int i = 0; i < n; i++)
    {
        if (vList[i]->e == nullptr)
            vList[i]->e = eList[i];

        // 推入半边
        m_eList.push_back(eList[i]);
    }
    delete[] eList;

    // 最后推入面
    m_fList.push_back(f);

    return f;
}

// 为一个面创建连接，会选择面的顶点相邻的面尝试建立连接
void MiniMesh::CreateTwin(face *f)
{
    std::deque<vertex3f *> vList = VertexOnFace(f);

    // 遍历整个面表，逐一尝试建立 twin 连接
    // 优化：不再遍历面表，而是选择与顶点相邻的面尝试建立 twin 连接；当面的数量较大时具有优势
    // 再优化：由于三角形顶点两两共用面，只需要计算两个顶点的邻面（有问题，不能只计算两个顶点，需要三个顶点都计算）
    // 注意要先取出所有邻面再建立连接，防止出现与自己连接的情况
    std::deque<face *> fList0 = AdjacentFace(vList[0]);
    std::deque<face *> fList1 = AdjacentFace(vList[1]);
    std::deque<face *> fList2 = AdjacentFace(vList[2]);
    for (auto it = fList0.begin(); it != fList0.end(); ++it)
        StitchFace(f, *it);
    for (auto it = fList1.begin(); it != fList1.end(); ++it)
        StitchFace(f, *it);
    for (auto it = fList2.begin(); it != fList2.end(); ++it)
        StitchFace(f, *it);
}

int MiniMesh::VertexNum() const
{
    return m_vList.size();
}

int MiniMesh::FaceNum() const
{
    return m_fList.size();
}

int MiniMesh::HalfEdgeNum() const
{
    return m_eList.size();
}

// 删除顶点
bool MiniMesh::DeleteVertex(vertex3f *v)
{
    if (v == nullptr)
        return false;

    // 获得所有相邻的面，将它们删除
    std::deque<face *> fList = AdjacentFace(v);
    for (auto it = fList.begin(); it != fList.end(); ++it)
        DeleteFace(*it);

    // 最后将 v 孤立
    v->e = nullptr;

    return true;
}

// 删除半边和相邻的面
bool MiniMesh::DeleteHalfEdge(half_edge *e)
{
    // 要求网格是三角形网格，要求对边必须存在
    if (m_type != MeshType::triangle || e == nullptr || e->twin == nullptr)
        return false;

    // 将 v2 合并到 v1
    vertex3f *v1 = e->v;
    vertex3f *v2 = Destination(e);

    // 获得需要操作的边，e11 与 e21 要配对，e12 与 e22 要配对
    half_edge *e11 = e->prev->twin;
    half_edge *e12 = e->twin->next->twin;
    half_edge *e21 = e->next->twin;
    half_edge *e22 = e->twin->prev->twin;

    // 这里记录 v1 将要保存的半边，因为删除面的操作可能使得 v1,v2 孤立
    half_edge *tmpe = nullptr;
    // 检查特殊情况：即 e11-e12 或 e21-e22 配对，这意味着两边重合，将会被删除，需要重新指定配对方式
    if (e11->twin != e12)
        tmpe = e11;
    // 如果 e11-e12，那么 e12->next 将会被删除，此半边无效
    if (e12->twin != e11)
        tmpe = e12->next;
    if (e21->twin != e22)
        tmpe = e21->next;
    if (e22->twin != e21)
        tmpe = e22;

    // 在删除面之前要先检查配对方式。正常的配对方式是 e11-e21, e12-e22
    // 但是，如果 e11,e12 或 e21,e22 原本就配对，意味着 e11,e12 或 e21,e22 将会被删除
    // 此时需要改变配对方式为 e21-e22 或 e11-e12
    int twinType = 0;
    if (e11->twin == e12)
        twinType = 1;
    if (e21->twin == e22)
        twinType = 2;
    // 有可能出现 e11-e12, e21-e22 的情况，但是这种情况在前面会造成 tmpe == nullptr，从而退出，这里不需要再考虑

    // 记录目标是 v1 的边数
    int count = 0;
    std::deque<half_edge *> eList = AdjacentHalfEdge(v2);
    for (int i = 0; i < eList.size(); i++)
    {
        if (Destination(eList[i]) == v1)
            count++;

        // 如果目标是 v1 的边数多于 1 个，说明在 v1-v2 构成的边上，存在多于 2 个半边
        // 但我们这里只删除 2 个半边，因此剩余的半边会叠合起来
        // 并且我们删除了一个顶点，之后对剩余半边进行收缩时就不会删除顶点，这里立即返回
        if (count > 1)
            return false;
    }

    // 以 v2 为起点的半边，将它们的起点都改为 v1
    for (int i = 0; i < eList.size(); i++)
        eList[i]->v = v1;

    // 令 v1 孤立，这样删除面时不需要再重新赋予 v1 半边
    v1->e = nullptr;

    // 进行删除操作，对于边收缩而言，会删除 1 到 2 个面
    // 第一个面是从 v1 指向 v2 的半边对应的面，这个面一定存在，因为 e 存在；第二个是该半边的反向边对应的面，不一定存在
    // 注意先删除 twin，不然 e 先被删除就成为 nullptr 了
    DeleteFace(e->twin->incFace);
    DeleteFace(e->incFace);

    // 令 v2 孤立，同时赋予 v1 新的半边
    v2->e = nullptr;
    v1->e = tmpe;

    // 基本配对方式
    if (twinType == 0)
    {
        e11->twin = e21;
        e21->twin = e11;
        e12->twin = e22;
        e22->twin = e12;
    }
    // e11-e12 的情况，配对 e21-e22
    else if (twinType == 1)
    {
        e21->twin = e22;
        e22->twin = e21;
    }
    // e21-e22 的情况，配对 e11-e12
    else
    {
        e11->twin = e12;
        e12->twin = e11;
    }

    return true;
}

// 删除面
bool MiniMesh::DeleteFace(face *f)
{
    if (f == nullptr)
        return false;

    // 获得三条半边，断言它们都非空
    std::deque<half_edge *> e = HalfEdgeOnFace(f);
    for (int i = 0; i < e.size(); ++i)
        if (e[i] == nullptr)
            return false;

    // 调整每条半边起点保存的半边
    for (int i = 0; i < e.size(); i++)
    {
        // 获得半边的起源点，和以 v 为起点的半边
        vertex3f *v = e[i]->v;
        if (v == nullptr)
            return false;

        // 当起点保存的半边是此半边时，就修改保存的半边。因此可以提前修改，这里就不会修改
        if (v->e == e[i])
        {
            // 删除面时，如果面上的顶点已经孤立，说明出现了非流形网格
            // 此时邻边的数量为零，应当重点注意
            std::deque<half_edge *> eList = AdjacentHalfEdge(v);

            // 如果 v 不止一条半边，就赋予新的半边，否则 v 将会孤立
            for (auto it = eList.begin(); it != eList.end(); ++it)
            {
                // 赋予不同的半边
                if ((*it) != e[i])
                {
                    v->e = *it;
                    break;
                }
            }
        }
    }

    // 删除每条半边
    for (int i = 0; i < e.size(); i++)
    {
        // 首先将每条半边的反向边的反向边设为空
        half_edge *te = e[i]->twin;
        if (te != nullptr)
            te->twin = nullptr;

        // 如果此半边的起点仍然持有此半边，那么起点将会孤立，将该点保有的半边设为空
        if (e[i]->v->e == e[i])
            e[i]->v->e = nullptr;

        // 将半边保有的顶点设为空
        e[i]->v = nullptr;
    }

    // 将面保有的半边设为空
    f->e = nullptr;

    return true;
}

// 清除孤立点
bool MiniMesh::DeleteIsolated(Element type)
{
    bool ifDelete = false;

    switch (type)
    {
    case Element::vertex:
    {
        // 找到所有孤立点删除
        for (auto it = m_vList.begin(); it != m_vList.end();)
        {
            // 如果不存在以它为起点的半边，说明此顶点孤立，直接删除
            if ((*it)->e == nullptr)
            {
                it = m_vList.erase(it);
                ifDelete = true;
            }
            else
                ++it;
        }
        break;
    }
    case Element::half_edge:
    {
        // 找到所有孤立边删除
        for (auto it = m_eList.begin(); it != m_eList.end();)
        {
            // 如果不存在半边起点，说明孤立
            if ((*it)->v == nullptr)
            {
                it = m_eList.erase(it);
                ifDelete = true;
            }
            else
                ++it;
        }
        break;
    }
    case Element::face:
    {
        // 找到所有孤立面删除
        for (auto it = m_fList.begin(); it != m_fList.end();)
        {
            // 如果不存在半边，说明孤立
            if ((*it)->e == nullptr)
            {
                it = m_fList.erase(it);
                ifDelete = true;
            }
            else
                ++it;
        }
        break;
    }
    }

    return ifDelete;
}

// 是否有法向
bool MiniMesh::HasVertexNormal()
{
    return !m_nList.empty();
}

// 判断网格是否是凸包
bool MiniMesh::IsConvexHull()
{
    // 对每个顶点，遍历每一个面
    for (auto vit = m_vList.begin(); vit != m_vList.end(); ++vit)
    {
        // 要排除离散点
        if ((*vit)->e == nullptr)
            continue;

        // 判断顶点是不是在所有面的上方，如果在某个面的上面，说明不是凸包
        for (auto fit = m_fList.begin(); fit != m_fList.end(); ++fit)
            if (AboveFace((*vit)->pos, *fit))
                return false;
    }

    return true;
}

// 判断点是否在网格的凸包中
bool MiniMesh::IsInMesh(Vector3f p)
{
    // 遍历每一个面，p 如果在某个面的上面，说明 p 在网格外
    for (auto it = m_fList.begin(); it != m_fList.end(); ++it)
        if (AboveFace(p, *it))
            return false;
    return true;
}

// “缝合”两个面，返回是否出错
bool MiniMesh::StitchFace(face *f1, face *f2)
{
    // 先取得公共半边
    std::deque<half_edge *> e = CommonOnFace(f1, f2);

    // 如果有公共边就连接，一种情况是如果已经建立，但是不是两个面的公共边，直接报错
    if (e[0] != nullptr && e[1] != nullptr)
    {
        if (e[0]->twin != nullptr && e[0]->twin != e[1])
            return false;
        if (e[1]->twin != nullptr && e[1]->twin != e[0])
            return false;

        // 然后互相为 twin
        e[0]->twin = e[1];
        e[1]->twin = e[0];
        return true;
    }
    // 没有公共边也报错
    return false;
}

// 判断一个点是否在面上
bool MiniMesh::OnFace(Vector3f p, face *f) const
{
    // 排除面是空的情况
    if (f == nullptr)
        return false;

    // 找到面的一个顶点
    Vector3f p0 = f->e->v->pos;
    Vector3f v = p - p0;

    // 如果与法向正交，说明共面
    return (fabs(dot(v, FaceNormal(f))) < ACCURACY) ? true : false;
}

// 判断一个点是否在面的上方
bool MiniMesh::AboveFace(Vector3f p, face *f) const
{
    // 排除面是空的情况
    if (f == nullptr)
        return false;

    // 取一个顶点计算夹角
    Vector3f p0 = f->e->v->pos;
    Vector3f v = p - p0;

    // 这里精度需要仔细考虑，不然判断会有问题
    return (dot(v, FaceNormal(f)) > ACCURACY) ? true : false;
}

// Gouraud 插值：计算顶点的平均法向
Vector3f MiniMesh::Gouraud(vertex3f *v) const
{
    // 先获取所有相邻的面
    std::deque<face *> fList = AdjacentFace(v);

    // 累加然后规范化
    Vector3f n = {0, 0, 0};
    for (auto it = fList.begin(); it != fList.end(); ++it)
        n = n + FaceNormal(*it);
    return normalize(n);
}

// 计算单位面法向
Vector3f MiniMesh::FaceNormal(face *f) const
{
    // 找到面的三个顶点计算法向
    Vector3f v0 = f->e->v->pos;
    Vector3f v1 = f->e->next->v->pos;
    Vector3f v2 = f->e->next->next->v->pos;
    return normalize(cross(v1 - v0, v2 - v1));
}

// 获得边的目标点
vertex3f *MiniMesh::Destination(half_edge *e) const
{
    if (e == nullptr)
        return nullptr;
    e = e->next;
    return e->v;
}

// 获得一个面上的所有顶点
std::deque<vertex3f *> MiniMesh::VertexOnFace(face *f) const
{
    half_edge *e = f->e;
    std::deque<vertex3f *> vList = {e->v};
    e = e->next;
    while (e != f->e)
    {
        vList.push_back(e->v);
        e = e->next;
    }
    return vList;
}

// 获得一个面上的所有半边
std::deque<half_edge *> MiniMesh::HalfEdgeOnFace(face *f) const
{
    half_edge *e = f->e;
    std::deque<half_edge *> eList = {e};
    e = e->next;
    while (e != f->e)
    {
        eList.push_back(e);
        e = e->next;
    }
    return eList;
}

// 获取两个面的公共半边
std::deque<half_edge *> MiniMesh::CommonOnFace(face *f0, face *f1) const
{
    std::deque<half_edge *> eList(2, nullptr);
    std::deque<half_edge *> eList0 = HalfEdgeOnFace(f0);
    std::deque<half_edge *> eList1 = HalfEdgeOnFace(f1);

    // 遍历两个面上的所有边
    for (int i = 0; i < eList0.size(); i++)
    {
        for (int j = 0; j < eList1.size(); j++)
        {
            half_edge *e0 = eList0[i];
            half_edge *e1 = eList1[j];

            // e0 的起点是 e1 的终点，e1 的起点是 e0 的终点时，说明是公共边，储存后直接返回
            if (e0->v == Destination(e1) && e1->v == Destination(e0))
            {
                eList[0] = e0;
                eList[1] = e1;
                return eList;
            }
        }
    }
    return eList;
}

// 获得相邻的所有顶点
std::deque<vertex3f *> MiniMesh::AdjacentVertex(vertex3f *v) const
{
    std::deque<vertex3f *> vList;

    // 先获得以 v 为起点的半边，其目标点就是相邻顶点
    std::deque<half_edge *> eList = AdjacentHalfEdge(v);
    for (int i = 0; i < eList.size(); i++)
        vList.push_back(Destination(eList[i]));

    // 当半边非空时才考虑
    if (!eList.empty())
    {
        // 注意考虑 twin 为空的情况，此时少算一个顶点
        // 第一种情况，只按照顺时针方向获得了半边，此时第一个半边的前一个半边的起点是少算的顶点
        if (eList.front()->prev->twin == nullptr)
            vList.push_back(eList.front()->prev->v);
        // 第二种情况，按照逆时针方向获得了半边，此时最后一个半边的前一个半边的起点是少算的顶点
        else if (eList.back()->prev->twin == nullptr)
            vList.push_back(eList.back()->prev->v);
    }

    return vList;
}

// 获得以 v 为起点的半边
std::deque<half_edge *> MiniMesh::AdjacentHalfEdge(vertex3f *v) const
{
    std::deque<half_edge *> eList;
    half_edge *e = v->e;

    // 先顺时针寻找
    while (e != nullptr)
    {
        eList.push_back(e);
        e = e->twin;

        // 反向边，然后找到下一条边
        if (e != nullptr)
            e = e->next;

        // 如果回到初始边，就退出
        if (e == v->e)
            break;
    }

    // 如果没有回到初始边，就逆时针寻找，排除孤立顶点
    if (e == nullptr && v->e != nullptr)
    {
        e = v->e->prev->twin;
        while (e != nullptr)
        {
            eList.push_back(e);
            e = e->prev->twin;
        }
        // 这里不需要判断回到初始边，因为如果一个方向不能返回，那么反过来也不能返回
    }
    return eList;
}

// 获得相邻的所有面
std::deque<face *> MiniMesh::AdjacentFace(vertex3f *v) const
{
    // 先获得以 v 为起点的半边
    std::deque<half_edge *> eList = AdjacentHalfEdge(v);

    // 每条半边左边的面就是相邻的面
    std::deque<face *> fList;
    for (auto it = eList.begin(); it != eList.end(); ++it)
        fList.push_back((*it)->incFace);

    return fList;
}

// 获得相邻的所有面
std::deque<face *> MiniMesh::AdjacentFace(face *f) const
{
    std::deque<face *> fList;
    std::deque<half_edge *> eList = HalfEdgeOnFace(f);
    for (int i = 0; i < eList.size(); i++)
        if (eList[i]->twin != nullptr)
            fList.push_back(eList[i]->twin->incFace);
    return fList;
}

// 取网格点沿着 pv 方向的投影多边形顶点
std::deque<vertex3f *> MiniMesh::MeshProject(Vector3f pv) const
{
    // 标记被照射的面，只需要保存一个面的指针，因为所有标记面都相邻
    std::deque<face *> fList;
    for (auto fit = m_fList.begin(); fit != m_fList.end(); ++fit)
    {
        // 如果法向与 pv 同向，说明被照射/投影正面
        Vector3f n = FaceNormal(*fit);
        if (dot(pv, n) > 0)
        {
            (*fit)->identity = 1;
            fList.push_back(*fit);
        }
        else
            (*fit)->identity = 0;
    }

    // 检查被照射的面，标记相邻的未照射面
    std::deque<half_edge *> eList;
    for (auto fit = fList.begin(); fit != fList.end(); fit++)
    {
        // 检查面上的半边，记录边界边
        std::deque<half_edge *> eList0 = HalfEdgeOnFace(*fit);
        for (int i = 0; i < eList0.size(); i++)
            if (eList0[i]->twin->incFace->identity != 1)
                eList.push_back(eList0[i]);
    }

    // 遍历所有反向边，按照连接顺序推入顶点
    auto eit = eList.begin();
    std::deque<vertex3f *> vList;
    while (vList.size() < eList.size())
    {
        vList.push_back((*eit)->v);
        // 找到目标点对应的边
        for (auto it = eList.begin(); it != eList.end(); ++it)
        {
            if ((*it)->v == Destination((*eit)))
            {
                eit = it;
                break;
            }
        }
    }

    return vList;
}

// 将网格三角化，返回三角化后的面列表
std::deque<face *> MiniMesh::TriangulateFace(face *f)
{
    // 获得所有顶点，如果恰好有三个，直接返回
    std::deque<vertex3f *> vList = VertexOnFace(f);
    if (vList.size() == 3)
        return {f};

    // 否则先删除面
    DeleteFace(f);

    // 遍历顶点创建
    std::deque<face *> fList;
    for (int i = 1; i < vList.size() - 1; i++)
        fList.push_back(CreateFace(vList[0], vList[i], vList[i + 1]));
    return fList;
}

// 设置网格材质
void MiniMesh::SetMaterial(float M[], float alpha)
{
    // 光照系数
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            m_material.R[i * 3 + j] = M[i * 3 + j];

    // 镜面反射系数
    m_material.alpha = alpha;
}

// 网格保存
bool MiniMesh::SaveMesh(const std::string &filename)
{
    // 根据保存名称修改网格名
    m_name = filename;

    // 首先输出各个属性的描述
    std::fstream fp(filename, std::ios::out);
    fp << "VertexNum " << VertexNum() << std::endl;
    fp << "FaceNum " << FaceNum() << std::endl;
    fp << "HasNormal " << HasVertexNormal() << std::endl;

    // 输出材质信息
    fp << "Material " << m_material.alpha << " ";
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            fp << m_material.R[i * 3 + j] << " ";
    fp << std::endl;

    // 然后输出顶点信息，并对顶点标号
    for (int i = 0; i < VertexNum(); i++)
    {
        Vector3f &pos = m_vList[i]->pos;
        m_vList[i]->identity = i;
        fp << "v " << pos.x() << " " << pos.y() << " " << pos.z() << std::endl;
    }
    // 输出面信息
    for (int i = 0; i < FaceNum(); i++)
    {
        fp << "f ";
        std::deque<vertex3f *> vList = VertexOnFace(m_fList[i]);

        // 先输出顶点数，然后输出顶点的索引
        fp << vList.size() << " ";
        for (int j = 0; j < vList.size(); j++)
            fp << vList[j]->identity << " ";

        // 对面编号
        m_fList[i]->identity = i;
        fp << std::endl;
    }
    // 输出邻面信息
    for (int i = 0; i < FaceNum(); i++)
    {
        fp << "a ";

        // 然后我们输出相邻面的索引
        std::deque<face *> fList = AdjacentFace(m_fList[i]);
        fp << fList.size() << " ";
        for (int j = 0; j < fList.size(); j++)
            fp << fList[j]->identity << " ";

        fp << std::endl;
    }

    // 如果有顶点法向就输出顶点法向
    if (HasVertexNormal())
    {
        for (int i = 0; i < VertexNum(); i++)
        {
            Vector3f &n = m_nList[i];
            fp << "n " << n.x() << " " << n.y() << " " << n.z() << std::endl;
        }
    }

    // 最后输出终止字符
    fp << "finish" << std::endl;

    return true;
}

// 网格读取
bool MiniMesh::LoadMesh(const std::string &filename, bool testSame)
{
    // 文件打不开报错
    std::fstream fp(filename, std::ios::in);
    if (!fp.is_open())
        return false;

    // 网格名就是文件名
    m_name = filename;

    std::string detail;
    float value;

    // 首先跳过各个属性的描述
    fp >> detail >> value;
    fp >> detail >> value;
    fp >> detail >> value;

    // 读取材质信息
    fp >> detail >> value;
    float M[9];
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            fp >> M[i * 3 + j];
    SetMaterial(M, value);

    // 暂存顶点，用于重合顶点的情形
    std::deque<vertex3f *> vList;

    // 然后根据第一个字符判断读取内容
    fp >> detail;
    while (detail == "v")
    {
        Real x, y, z;
        fp >> x >> y >> z;

        // 禁止重合顶点的检测
        vertex3f *v = CreateVertex({x, y, z}, testSame);
        if (testSame)
            vList.push_back(v);
        fp >> detail;
    }
    // 长度为 6 就足够了，至多六边形网格
    vertex3f *v[6];
    while (detail == "f")
    {
        int i, n;
        fp >> n;

        // 检查长度
        if (n > 6)
            return false;

        // 当开启检测时，使用记录列表中的顶点
        for (int j = 0; j < n; j++)
        {
            fp >> i;
            v[j] = testSame ? vList[i] : m_vList[i];
        }

        // 由于后面会进行衔接操作，因此创建面时取消自动衔接
        CreateFace(v, n, false);
        fp >> detail;
    }
    int i = 0;
    while (detail == "a")
    {
        int size, j;

        // 获得邻面索引信息，然后对这些面进行衔接
        fp >> size;
        for (int k = 0; k < size; k++)
        {
            fp >> j;
            StitchFace(m_fList[i], m_fList[j]);
        }
        fp >> detail;
        i++;
    }
    while (detail == "n")
    {
        Real x, y, z;
        fp >> x >> y >> z;
        m_nList.push_back(Vector3f(x, y, z));
        fp >> detail;
    }

    return true;
}

// 球面：中心位置、三个半长轴，分割份数
bool XYF::sphere(MiniMesh *mesh, Vector3f center, Vector3f axis, Real a, Real b, Real c, int div)
{
    // 首先检查参数有效性，分割份数至少应该是 2
    if (mesh == nullptr || div < 1)
        return false;

    // 把 a,b,c 都换成正的
    a = fabs(a);
    b = fabs(b);
    c = fabs(c);

    // 使用极坐标取点，获得纵向步长，也是横向步长
    const Real PI = 3.1415926;
    Real dphi = PI / div;
    Real phi = dphi;
    Real theta = 0;

    // 获得从 z 轴转动到 axis 的四元数
    axis = normalize(axis);
    Quaternion q({0, 0, 1}, axis);

    // 不创建极点，i 是纵向，因此纵向点的数量少一些，j 是横向，横向分割份数是纵向的 2 倍
    for (int i = 0; i < div - 1; i++)
    {
        for (int j = 0; j < div * 2; j++)
        {
            // 先记录一个纯四元数，将其转动
            Quaternion p(0, {a * sin(phi) * cos(theta), b * sin(phi) * sin(theta), c * cos(phi)});
            p = q * p / q;
            mesh->CreateVertex({p.v().x() + center.x(), p.v().y() + center.y(), p.v().z() + center.z()});
            theta += dphi;
        }
        theta = 0;
        phi += dphi;
    }

    // 现在创建这些点构成的面，每一行和上一行构成面
    for (int i = 1; i < div - 1; i++)
    {
        for (int j = 0; j < div * 2; j++)
        {
            vertex3f *v0 = mesh->m_vList[i * (div * 2) + j];
            vertex3f *v1 = mesh->m_vList[i * (div * 2) + (j + 1) % (div * 2)];
            vertex3f *v2 = mesh->m_vList[(i - 1) * (div * 2) + (j + 1) % (div * 2)];
            vertex3f *v3 = mesh->m_vList[(i - 1) * (div * 2) + j];
            mesh->CreateFace(v0, v1, v2, v3);
        }
    }

    // 最后创建极点，连接极点和相邻的点
    Vector3f up = center + axis * c;
    mesh->CreateVertex(up);
    for (int j = 0; j < div * 2; j++)
    {
        vertex3f *v0 = mesh->m_vList[j];
        vertex3f *v1 = mesh->m_vList[(j + 1) % (div * 2)];
        vertex3f *v2 = mesh->m_vList.back();
        mesh->CreateFace(v0, v1, v2);
    }

    Vector3f dp = center + axis * -c;
    mesh->CreateVertex(dp);
    for (int j = 0; j < div * 2; j++)
    {
        vertex3f *v0 = mesh->m_vList[(div - 2) * (div * 2) + j];
        vertex3f *v1 = mesh->m_vList[(div - 2) * (div * 2) + (j + 1) % (div * 2)];
        vertex3f *v2 = mesh->m_vList.back();
        mesh->CreateFace(v1, v0, v2);
    }
    return true;
}

// 柱面：中心位置，中轴，半径，高度，分割份数
bool XYF::cylinder(MiniMesh *mesh, Vector3f center, Vector3f axis, Real r, Real h, int divr, int divh)
{
    // 首先检查参数有效性，分割份数至少应该是 2
    if (mesh == nullptr || divr < 1 || divh < 1)
        return false;

    // 把 r,h 都换成正的
    r = fabs(r);
    h = fabs(h);

    // 使用极坐标取点，获得纵向步长，和横向步长
    const Real PI = 3.1415926;
    Real dtheta = 2 * PI / divr;
    Real theta = 0;
    Real dh = h / divh;

    // 获得从 z 轴转动到 axis 的四元数
    Quaternion q({0, 0, 1}, axis);

    Real nz = -h / 2;
    // 从下向上依次创建顶点
    for (int i = 0; i < divh + 1; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            // 先记录一个纯四元数，将其转动
            Quaternion p(0, {r * cos(theta), r * sin(theta), nz});
            p = q * p / q;
            mesh->CreateVertex({p.v().x() + center.x(), p.v().y() + center.y(), p.v().z() + center.z()});
            theta += dtheta;
        }
        theta = 0;
        nz += dh;
    }

    // 现在创建这些点构成的面，每一行和上一行构成面
    for (int i = 0; i < divh; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            vertex3f *v0 = mesh->m_vList[i * divr + j];
            vertex3f *v1 = mesh->m_vList[i * divr + (j + 1) % divr];
            vertex3f *v2 = mesh->m_vList[(i + 1) * divr + (j + 1) % divr];
            vertex3f *v3 = mesh->m_vList[(i + 1) * divr + j];
            mesh->CreateFace(v0, v1, v2, v3);
        }
    }

    // 创建上下两个面的中点
    Quaternion p1(0, {0, 0, -h / 2});
    Quaternion p2(0, {0, 0, h / 2});
    p1 = q * p1 / q;
    p2 = q * p2 / q;
    vertex3f *c1 = mesh->CreateVertex({p1.v().x() + center.x(), p1.v().y() + center.y(), p1.v().z() + center.z()});
    vertex3f *c2 = mesh->CreateVertex({p2.v().x() + center.x(), p2.v().y() + center.y(), p2.v().z() + center.z()});

    // 建立上下两个面
    for (int i = 0; i < divr; i++)
    {
        vertex3f *v0 = mesh->m_vList[i];
        vertex3f *v1 = mesh->m_vList[(i + 1) % divr];
        mesh->CreateFace(c1, v1, v0);

        vertex3f *v2 = mesh->m_vList[divh * divr + i];
        vertex3f *v3 = mesh->m_vList[divh * divr + (i + 1) % divr];
        mesh->CreateFace(v2, v3, c2);
    }

    return true;
}

// 锥面：中心位置，中轴，半角，高度，分割份数
bool XYF::cone(MiniMesh *mesh, Vector3f origin, Vector3f axis, Real theta, Real h, int divr, int divh)
{
    // 首先检查参数有效性，分割份数至少应该是 2
    if (mesh == nullptr || theta <= 0 || divr < 1 || divh < 1)
        return false;

    // 把 h 换成正的，theta 转换为弧度
    const Real PI = 3.1415926;
    h = fabs(h);
    theta = theta / 180 * PI;

    // 使用极坐标取点，获得纵向步长，和横向步长
    Real dphi = 2 * PI / divr;
    Real phi = 0;
    Real dh = h / divh;

    // 获得从 z 轴转动到 axis 的四元数
    Quaternion q({0, 0, 1}, axis);

    // 先跳过极点
    Real nz = dh;
    // 从下向上依次创建顶点
    for (int i = 0; i < divh; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            // 先记录一个纯四元数，将其转动
            Real r = nz * tan(theta);
            Quaternion p(0, {r * cos(phi), r * sin(phi), nz});
            p = q * p / q;
            mesh->CreateVertex({p.v().x() + origin.x(), p.v().y() + origin.y(), p.v().z() + origin.z()});
            phi += dphi;
        }
        phi = 0;
        nz += dh;
    }

    // 现在创建这些点构成的面，每一行和上一行构成面
    for (int i = 0; i < divh - 1; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            vertex3f *v0 = mesh->m_vList[i * divr + j];
            vertex3f *v1 = mesh->m_vList[i * divr + (j + 1) % divr];
            vertex3f *v2 = mesh->m_vList[(i + 1) * divr + (j + 1) % divr];
            vertex3f *v3 = mesh->m_vList[(i + 1) * divr + j];
            mesh->CreateFace(v0, v1, v2, v3);
        }
    }

    // 最后创建锥顶，连接第一行
    mesh->CreateVertex(origin);
    for (int j = 0; j < divr; j++)
    {
        vertex3f *v0 = mesh->m_vList[j];
        vertex3f *v1 = mesh->m_vList[(j + 1) % divr];
        vertex3f *v2 = mesh->m_vList.back();
        mesh->CreateFace(v2, v1, v0);
    }

    // 创建下面的中点
    Quaternion p(0, {0, 0, h});
    p = q * p / q;
    mesh->CreateVertex({p.v().x() + origin.x(), p.v().y() + origin.y(), p.v().z() + origin.z()});

    // 建立下面
    for (int j = 0; j < divr; j++)
    {
        vertex3f *v0 = mesh->m_vList[(divh - 1) * divr + j];
        vertex3f *v1 = mesh->m_vList[(divh - 1) * divr + (j + 1) % divr];
        vertex3f *v2 = mesh->m_vList.back();
        mesh->CreateFace(v0, v1, v2);
    }

    return true;
}

// 圆环面：中心位置，垂直轴，内径，外径，分割份数
bool XYF::ring(MiniMesh *mesh, Vector3f center, Vector3f axis, Real r, Real R, int divR, int divr)
{
    // 首先检查参数有效性，分割份数至少应该是 2
    if (mesh == nullptr || divr < 1 || divR < 1 || fabs(R) <= fabs(r))
        return false;

    // 把 R,r 换成正的
    const Real PI = 3.1415926;
    R = fabs(R);
    r = fabs(r);

    // 使用极坐标取点，大圆步长和小圆步长
    Real dRa = 2 * PI / divR;
    Real dra = 2 * PI / divr;
    Real Ra = 0;
    Real ra = 0;
    Real mR = (R + r) / 2;
    Real mr = (R - r) / 2;

    // 获得从 z 轴转动到 axis 的四元数
    Quaternion q({0, 0, 1}, axis);

    // 转动创建顶点
    for (int i = 0; i < divR; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            // 先记录一个纯四元数，将其转动
            Quaternion p(0, {(mR + mr * sin(ra)) * cos(Ra), (mR + mr * sin(ra)) * sin(Ra), mr * cos(ra)});
            p = q * p / q;
            mesh->CreateVertex({p.v().x() + center.x(), p.v().y() + center.y(), p.v().z() + center.z()});
            ra += dra;
        }
        ra = 0;
        Ra += dRa;
    }

    // 现在创建这些点构成的面，每一行和上一行构成面
    for (int i = 0; i < divR; i++)
    {
        for (int j = 0; j < divr; j++)
        {
            vertex3f *v0 = mesh->m_vList[i * divr + j];
            vertex3f *v1 = mesh->m_vList[i * divr + (j + 1) % divr];
            vertex3f *v2 = mesh->m_vList[((i + 1) % divR) * divr + (j + 1) % divr];
            vertex3f *v3 = mesh->m_vList[((i + 1) % divR) * divr + j];
            mesh->CreateFace(v0, v1, v2, v3);
        }
    }
    return true;
}
